package cfg.mpsc.gui;

import instrumenter.ExecutedNode;
import instrumenter.MethodExecutionInstrumenter;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.filechooser.FileFilter;

import cern.colt.Arrays;
import cfg.gui.CFGUIContext;
import cfg.model.CFGNode;
import cfg.mpsc.EdgesPath;
import cfg.mpsc.IEdge;
import cfg.mpsc.INode;
import cfg.mpsc.MPSC;
import cfg.mpsc.Path;
import cfg.mpsc.PathProcessor;
import model.SysMethod;
import model.SysRoot;
import instrumenter.utils.*;

public class MPSCWindow extends JFrame {

	private SysMethod m;
	private SysRoot root;
	private JTextField junitTest;
	private JButton junitTestButton;
	private JTextField mpscPoints;
	private JTextField mpscGap;
	private JButton run;
	private String[] classPath;
	
	public static final String tempDir = ".tempExecution"; 
	
	private static final String junitSelect = "SELECT JUNIT TEST CLASS";
	
	public MPSCWindow(SysMethod m, SysRoot root, String[] classPath) {
		super("Options for: "+m);
		this.m=m;
		this.root=root;
		this.classPath=classPath;
		this.setLayout(new GridLayout(0,2));
		junitTest = new JTextField(junitSelect);
		junitTest.setEditable(true);
		junitTestButton = new JButton("select");
		junitTestButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				//select .class file
				JFileChooser fc = new JFileChooser();
				fc.setFileFilter(new FileFilter(){
					@Override
					public boolean accept(File arg0) {
						return arg0.getName().endsWith(".class") || arg0.isDirectory();
					}
					@Override
					public String getDescription() {
						return "Java bytecode \".class\" file";
					}
				});
				fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
				if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
					junitTest.setText(fc.getSelectedFile().getAbsolutePath());
				}
			}
		});
		this.mpscGap=new JTextField("1");
		this.mpscPoints=new JTextField("1");
		this.run = new JButton("Instrument and Run");
		run.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				MethodExecutionInstrumenter inst=null;
				CFGNode cfg = CFGUIContext.CFG_BUILDER.build(MPSCWindow.this.m);
				cfg.setSysMethod(CFGUIContext.currentAnalysedMethod);
				CFGUIContext.allCurrentCFGNodes.add(cfg);
				try {
					inst = new MethodExecutionInstrumenter(MPSCWindow.this.m.getMethod());
					inst.instrument(cfg);
				} catch (ClassNotFoundException e) {
					JOptionPane.showMessageDialog(null, "Could not instrument method "+MPSCWindow.this.m.toString());
					e.printStackTrace();
					return;
				}
				try {
					FileUtil.deleteFolder(".tempExecution");
					FileUtil.copyFolder(MPSCWindow.this.root.getPath(), ".tempExecution");
				} catch (IOException e) {
					JOptionPane.showMessageDialog(null, "Could not copy workint set "+MPSCWindow.this.root.getPath());
					e.printStackTrace();
					return;
				}
				try {
					inst.dump(".tempExecution");
				} catch (IOException e) {
					JOptionPane.showMessageDialog(null, "Could not save instrumented method: "+MPSCWindow.this.m);
					e.printStackTrace();
					return;
				}
				//run JUnit, and add logger class to class path
				MPSC.runJunit(new File(tempDir), junitTest.getText(), MPSCWindow.this.classPath);
				//load path execution
				INode start = ExecutedNode.processList(tempDir+File.separator+"trace.log");
				//Path p = new Path(start);
				/*while(start!=null){
					System.out.println(start.getBytecodenumber());
					if(start.nextNodes()==null || start.nextNodes().isEmpty()){
						start=null;
					} else {
						start=start.nextNodes().get(0);
					}
				}*/
				//generate tuples from execution
				//List<List<IEdge>> execTuples = p.toEdgesPath().mpscTuples();
				Integer gap = Integer.valueOf(mpscGap.getText());
				Integer points = Integer.valueOf(mpscPoints.getText());
				//there is just one executed path
				List<List<IEdge>> execTuples = new PathProcessor(start).process().get(0).toEdgesPath().mpscTuples(gap,points);
				
				//generate tuples from static method
				List<List<IEdge>> staticTuples=new ArrayList<List<IEdge>>();
				for(Path p : new PathProcessor(cfg).process()){
					for(List<IEdge> newPath : p.toEdgesPath().mpscTuples(gap, points)){
						if(!staticTuples.toString().contains(newPath.toString())){
							staticTuples.add(newPath);
						}
					}
					
				}
				
				System.out.println("executed tuples: ");
				System.out.println(execTuples);
				System.out.println("generated tuples: ");
				System.out.println(staticTuples);
			}
			
		});
		this.add(junitTest);
		this.add(junitTestButton);
		this.add(mpscGap);
		this.add(new JLabel("gap"));
		this.add(mpscPoints);
		this.add(new JLabel("# points"));
		this.add(new JLabel(""));
		this.add(run);
		
		
		
		this.pack();
		this.setVisible(true);
	}

}
